﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using System.Xml;

namespace TaskLib
{
    public class SimpleTaskFactory : ITaskFactory
    {        
        private List<Task> tasks = new List<Task>();
        public ReadOnlyCollection<Task> Tasks
        {
            get { return this.tasks.AsReadOnly(); }
        }

        public event TasksChangedEventHandler TasksChanged;

        private long nextId = 0;

        public Task CreateTask(string description, DateTime scheduled, string comment, bool notify)
        {
            Task task = new Task(nextId, description, scheduled, comment);
            tasks.Add(task);
            nextId++;
            if (notify)
            {
                if (TasksChanged != null)
                {
                    TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                }
            }
            return task;
        }

        public void UpdateTaskDescription(long id, string description)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                if (description != null)
                {
                    if (task.Description.CompareTo(description) != 0)
                    {
                        task.Description = description;
                        if (TasksChanged != null)
                        {
                            TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                        }
                    }
                }
            }
        }

        public void UpdateTaskScheduled(long id, DateTime scheduled)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                if (task.Scheduled != scheduled)
                {
                    task.Scheduled = scheduled;
                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                    }
                }
            }
        }

        public void UpdateTaskCompleted(long id, bool completed)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                if (task.Completed != completed)
                {
                    task.Completed = completed;
                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                    }
                }
            }
        }

        public void UpdateTaskComment(long id, string comment)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                if (comment != null)
                {
                    if (task.Comment.CompareTo(comment) != 0)
                    {
                        task.Comment = comment;
                    }
                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                    }
                }
            }
        }

        public void UpdateTask(long id, string description, DateTime scheduled, string comment = null)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                bool taskChanged = false;

                if (description != null)
                {
                    task.Description = description;
                    taskChanged = true;
                }
                if (scheduled != DateTime.MinValue)
                {
                    task.Scheduled = scheduled;
                    taskChanged = true;
                }
                if (comment != null)
                {
                    task.Comment = comment;
                    taskChanged = true;
                }

                if (taskChanged)
                {
                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                    }
                }
            }
        }   

        public bool MarkCompleted(long id, DateTime completed)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                task.Completion = completed;
                if (TasksChanged != null)
                {
                    TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                }
                return true;
            }
            return false;
        }

        public bool MarkCompleted(long id)
        {
            return MarkCompleted(id, DateTime.Now);
        }

        private Task GetTask(long id)
        {
            foreach (Task task in tasks)
            {
                if (task.ID == id)
                {
                    return task;
                }
            }
            return null;
        }
        
        public void UpdateTaskCompletion(long id, DateTime completion)
        {
            Task task = GetTask(id);
            if (task != null)
            {
                if (task.Completion != completion)
                {
                    task.Completion = completion;
                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, new Task[] { task }));
                    }
                }
            }
        }


        public void SerializeTasks(string file)
        {
            using (var xmlWriter = new XmlTextWriter(file, Encoding.Unicode))
            {
                var xmlSerializer = new XmlSerializer(tasks.GetType());
                xmlSerializer.Serialize(xmlWriter, tasks);                   
            }                        
        }

        public void DeserializeTasks(string file)
        {
            try
            {
                using (var xmlReader = new XmlTextReader(file))
                {
                    var xmlSerializer = new XmlSerializer(tasks.GetType());
                    tasks = xmlSerializer.Deserialize(xmlReader) as List<Task>;

                    if (TasksChanged != null)
                    {
                        TasksChanged(new TasksChangedEventArgs(this, Tasks, tasks.ToArray<Task>()));
                    }
                }
            }
            catch (InvalidOperationException ioe)
            {
            }
        }
    }
}
